# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: LightSwitchDriver.py
  @time: 2022/4/17 14:13
  @desc:
"""

import socket
import time
import threading


def initialize(ipv4_address_string_in, port_in=5000, timeout_in_seconds_in=5):
    return switch_init(ipv4_address_string_in, port_in, timeout_in_seconds_in)


def switch_init(ipv4_address_string_in, port_in, timeout_in_seconds_in):
    light_switch_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    light_switch_instance.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 设置缓冲区
    # Set the timeout
    if timeout_in_seconds_in > 0:
        light_switch_instance.setblocking(False)
        light_switch_instance.settimeout(timeout_in_seconds_in)
    else:
        light_switch_instance.setblocking(True)
    light_switch_instance.connect((ipv4_address_string_in, port_in))
    return light_switch_instance


def close(light_session_in):
    try:
        light_session_in.shutdown(socket.SHUT_RDWR)
    finally:
        light_session_in.close()


# Sets timeout
def set_timeout(light_session_in, timeout_in_seconds_in):
    # Set the timeout
    if timeout_in_seconds_in > 0:
        light_session_in.setblocking(False)
        light_session_in.settimeout(timeout_in_seconds_in)
    else:
        light_session_in.setblocking(True)


def write(light_session_in, light_command_in, debug_light_in=False):
    # Print the input if debug
    if debug_light_in:
        print('Debug Command Sent: ' + light_command_in)
    # Add the newline
    light_session_in.send(light_command_in.encode())
    return light_session_in.recv(1024).decode()


def query(light_session_in, query_command_in, input_buffer_size_in_bytes_in=1024, debug_light_in=False):
    if debug_light_in:
        print("debug......")
    return write(light_session_in, query_command_in, debug_light_in=debug_light_in)


class LightSwitchDriver:
    # _instance_lock = threading.Lock()

    # 构造函数
    def __init__(self, address_in="192.168.1.111", port_in=5000, timeout_in_seconds_in=10, connect_in=True,
                 debug_light_in=False):
        # Start a session
        self.__is_connected = False
        self.__ipv4_address = address_in
        self.__address = address_in
        self.__port = port_in
        self.__timeout_in_seconds = timeout_in_seconds_in
        self.__debug_mode_mpi = debug_light_in
        if connect_in:
            self.__light_session = initialize(ipv4_address_string_in=address_in,
                                              timeout_in_seconds_in=timeout_in_seconds_in)
            self.__is_connected = True

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(LightSwitchDriver, "_instance"):
            LightSwitchDriver._instance = LightSwitchDriver(*args, **kwargs)
        return LightSwitchDriver._instance

    @property
    def light_session(self):
        return self.__light_session

    # IPV4 Address
    @property
    def ipv4_address(self):
        return self.__address

    # port
    @property
    def port(self):
        return self.__port

    # Timeout
    @property
    def timeout_in_seconds(self):
        return self.__timeout_in_seconds

    @timeout_in_seconds.setter
    def timeout_in_seconds(self, value):
        self.__timeout_in_seconds = value
        if self.__is_connected:
            set_timeout(light_session_in=self.__light_session,
                        timeout_in_seconds_in=self.__timeout_in_seconds)

    # Termination Character
    @property
    def termination_char(self):
        return self.__termination_char

    @termination_char.setter
    def termination_char(self, value):
        self.__termination_char = value

    # Is Connected
    @property
    def is_connected(self):
        return self.__is_connected

    # Debug SCPI
    @property
    def debug_mode_light(self):
        return self.__debug_mode_mpi

    @debug_mode_light.setter
    def debug_mode_light(self, value):
        self.__debug_mode_mpi = value

    # Methods
    # Connect if not/dis_connected
    def connect(self, timeout_in_seconds_in=None):
        # Disconnect if connected
        if self.__is_connected:
            try:
                close(light_session_in=self.__light_session)
            finally:
                self.__is_connected = False

        # Reconnect
        # Start a session
        if timeout_in_seconds_in is not None:
            self.__timeout_in_seconds = timeout_in_seconds_in
        self.__light_session = initialize(ipv4_address_string_in=self.__ipv4_address,
                                          timeout_in_seconds_in=self.__timeout_in_seconds, port_in=self.__port)
        self.__is_connected = True

    # Disconnect
    def disconnect(self):
        """
        Disconnect from the instrument
        :return:
        """
        # Disconnect if connected
        if self.__is_connected:
            try:
                close(light_session_in=self.__light_session)

            finally:
                self.__is_connected = False

    def set_single_switch(self, switch_combination, swith_number):
        """
        :param switch_combination: AA;BB
        :param swith_number: AA:{01/02};BB:{05/06}
        :return:
        """

        cmd = f"<OSW01_OUT_{switch_combination}_{swith_number}>"
        write(self.__light_session, cmd)

    def set_all_switch(self, switch_number01, switch_number02):
        """
        :param switch_number01:01/02
        :param switch_number02:05/06
        :return:
        """

        cmd = f"<OSW01_OUT_{switch_number01}_{switch_number02}>"
        return write(self.__light_session, cmd)

    def query_switch(self):
        cmd = "<OSW01_OUT_?>"
        return query(self.__light_session, cmd)


#
# switch_inst = LightSwitchDriver.instance()
# print(switch_inst.set_all_switch("01", "05"))
# print(switch_inst.query_switch())
